home *** CD-ROM | disk | FTP | other *** search
/ Super PC 31 / Super PC 31 (Shareware).iso / spc / inter / speakf / fuente / connect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-30  |  47.6 KB  |  1,534 lines

  1. /*
  2.  
  3.     Window procedure for connection MDI window
  4.     
  5. */
  6.  
  7. #include "netfone.h"
  8.  
  9. #define ASYNC_OUTPUT
  10.                             
  11. static struct {
  12.     char header[4];
  13.     unsigned short len, ilen;
  14.     soundbuf sbm;
  15. } mb = {{1, 2, 3, 4}};
  16. #define sb    mb.sbm
  17.  
  18. soundbuf ebuf;                            // Utility sound buffer
  19. static struct adpcm_state adpcm;      // ADPCM compression state
  20.  
  21. extern long outputPending;
  22. char blankit[] = "                                                              "
  23.                  "                                                              "
  24.                  "                                                              ";
  25.  
  26. /*  GSMCOMP  --  Compress the contents of a sound buffer using GSM.  */
  27.  
  28. static void gsmcomp(soundbuf *asb)
  29. {
  30.     gsm_signal src[160];
  31.     gsm_frame dst;
  32.     int i, j, l = 0;
  33.     char *dp = (asb->buffer.buffer_val) + sizeof(short);
  34.     long ldata = asb->buffer.buffer_len; 
  35.     
  36.     for (i = 0; i < ldata; i += 160) {
  37.         for (j = 0; j < 160; j++) {
  38.             if ((i + j) < asb->buffer.buffer_len) {
  39.                 src[j] = audio_u2s(asb->buffer.buffer_val[i + j]);
  40.             } else {
  41.                 src[j] = 0;
  42.             }
  43.         }
  44.         gsm_encode(gsmh, src, dst);
  45.         _fmemcpy(dp, dst, sizeof dst);
  46.         dp += sizeof dst;
  47.         l += sizeof dst;
  48.     }
  49.  
  50.     /* Hide original uncompressed buffer length in first 2 bytes of buffer. */
  51.     
  52.     *((short *) asb->buffer.buffer_val) = (short) ldata;
  53.     revshort((short *) asb->buffer.buffer_val);
  54.     asb->buffer.buffer_len = l + sizeof(short);
  55. }
  56.  
  57. /*    ADPCMCOMP  --  Compress the contents of a sound buffer using ADPCM.  */
  58.  
  59. static void adpcmcomp(soundbuf *asb)
  60. {
  61.     unsigned char *dp = (unsigned char *) asb->buffer.buffer_val;
  62.     struct adpcm_state istate;
  63.  
  64.     istate = adpcm;
  65.     adpcm_coder_u(dp, (char *) dp, (int) asb->buffer.buffer_len, &adpcm);
  66.     asb->buffer.buffer_len /= 2;
  67.  
  68.     /* Hide the ADPCM encoder state at the end of this buffer.
  69.        The shifting and anding makes the code byte-order
  70.        insensitive. */
  71.  
  72.     dp += asb->buffer.buffer_len;
  73.     *dp++ = ((unsigned int) istate.valprev) >> 8;
  74.     *dp++ = istate.valprev & 0xFF;
  75.     *dp = istate.index;
  76.     asb->buffer.buffer_len += 3;
  77. }
  78.  
  79. /*    LPCCOMP  --  Compress the contents of a sound buffer using LPC.  */
  80.  
  81. static void lpccomp(asb)
  82.   struct soundbuf *asb;
  83. {
  84.     int i, l = 0;
  85.     char *dp = ((char *) asb->buffer.buffer_val) + sizeof(short);
  86.     unsigned char *src = ((unsigned char *) asb->buffer.buffer_val);
  87.     lpcparams_t lp;
  88.  
  89.     asb->compression |= fCompLPC;
  90.     for (i = 0; i < asb->buffer.buffer_len; i += 180) {
  91.         lpc_analyze(src + i, &lp);
  92.         revshort(&(lp.period));
  93.         _fmemcpy(dp, &lp, sizeof lp);
  94.         dp += sizeof lp;
  95.         l += sizeof lp;
  96.     }
  97.  
  98.     // Hide original uncompressed buffer length in first 2 bytes of buffer.
  99.  
  100.     *((short *) asb->buffer.buffer_val) = (short) asb->buffer.buffer_len;
  101.     revshort((short *) asb->buffer.buffer_val);
  102.     asb->buffer.buffer_len = l + sizeof(short);
  103. }
  104.  
  105. /*  COMPRESS2X  --  Compress a sound buffer with Simple (discard every
  106.                     other sample) compression.  If you're doing both
  107.                     Simple and GSM compression, Simple compression must be
  108.                     done first.  */
  109.                     
  110. void compress2X(soundbuf *asb)
  111. {
  112.     LONG i;
  113.              
  114.     asb->buffer.buffer_len /= 2;
  115.     for (i = 1; i < asb->buffer.buffer_len; i++) {
  116.         asb->buffer.buffer_val[i] = asb->buffer.buffer_val[i * 2];
  117.     }
  118. }
  119.  
  120. //    WRITEOUTPUT  --  Transmit output buffer to destination
  121.  
  122. static int writeOutput(LPCLIENT_DATA d, LPSTR buf, int buflen)
  123. {
  124.     if (d->modemConnection) {
  125.         if (modemHandle != -1) {
  126.             unsigned short bcrc;
  127.             COMSTAT cs;
  128.             int wrl, err;
  129.         
  130.             mb.len = (unsigned short) buflen;
  131.             mb.ilen = ~mb.len;
  132.             revshort(&mb.len);
  133.             revshort(&mb.ilen);
  134.             bcrc = crc((LPSTR) &mb, buflen + 4 + 2 * sizeof(unsigned short));
  135.             revshort(&bcrc);
  136.             err = GetCommError(modemHandle, &cs);
  137.             if (err != 0) { 
  138.                 MsgBox(hwndMDIFrame, MB_ICONSTOP | MB_OK, Format(20), err);
  139.                 errorRant(hwndMDIFrame);
  140.                 return -1;
  141.             } 
  142.             wrl = WriteComm(modemHandle, &mb, buflen + 4 + 2 * sizeof(unsigned short));
  143.             err = GetCommError(modemHandle, &cs);
  144.             if (err != 0) { 
  145.                 MsgBox(hwndMDIFrame, MB_ICONSTOP | MB_OK, Format(21), err);
  146.                 errorRant(hwndMDIFrame);
  147.                 return -1;
  148.             } 
  149.             if (wrl > 0) {
  150.                 wrl = WriteComm(modemHandle, &bcrc, sizeof(short));
  151.             }
  152.             err = GetCommError(modemHandle, &cs);
  153.             if (err != 0) { 
  154.                 MsgBox(hwndMDIFrame, MB_ICONSTOP | MB_OK, Format(22), err);
  155.                 errorRant(hwndMDIFrame);
  156.                 return -1;
  157.             }
  158.             return buflen;
  159.         }
  160.     } else {
  161.         int stat;
  162.         
  163.         if ((!useSendNotSendto || waNetNoConnect) && (!waNetUseSend)) {
  164. //if (packetsSent == 200) { stat = -1; } else        
  165.             stat = sendto(d->sReply, buf, buflen, 0,
  166.                     (LPSOCKADDR) &(d->name), sizeof d->name);
  167.             if (stat < 0) {
  168.                 if (!waNetNoConnect) {
  169.                     useSendNotSendto = TRUE;
  170.                     if (hDlgPropeller != NULL) {
  171.                         SetDlgItemText(hDlgPropeller, IDC_PH_SENDTO, rstring(IDS_T_SEND));
  172.                     }
  173.                 }
  174.             }
  175.         }
  176.         /*    Careful!  Don't "optimise" this to "else if"; we have to be
  177.             able to switch-hit when the first sendto() fails above. */
  178.         if (useSendNotSendto) {
  179.             stat = send(d->sReply, buf, buflen, 0);
  180.         }
  181.         if (stat >= 0) {
  182.             d->outputSocketBusy = TRUE;
  183.             propeller(IDC_PH_PACKETS_SENT, ++packetsSent);
  184.         } else {
  185.             propeller(IDC_PH_OUTPUT_LOST, ++outputPacketsLost);
  186.         }        
  187.         return stat;
  188.     }
  189. }
  190.  
  191. //    SOCKETERRORBOX  --  Show message box for socket error
  192.  
  193. static void socketerrorbox(HWND hwnd, LPCLIENT_DATA d)
  194. {
  195.     if (d->modemConnection) {
  196.         MessageBox(hwnd, rstring(IDS_T_MODEM_WRITE_ERR), NULL,
  197.             MB_ICONEXCLAMATION | MB_OK);
  198.     } else {
  199.         MessageBox(hwnd, SockerrToString(WSAGetLastError()), rstring(IDS_T_SOCKET_WRITE_ERR),
  200.             MB_ICONEXCLAMATION | MB_OK);
  201.     }
  202.  
  203. /*  SENDPKT  --  Send a message to the destination.  */
  204.  
  205. static int sendpkt(HWND hwnd, LPCLIENT_DATA d, struct soundbuf *asb)
  206. {
  207.     LONG lts = asb->buffer.buffer_len;
  208.  
  209.     if (d->deskey[0] || d->ideakey[0] || d->opgpkey[0] || d->otpFileName[0]) {
  210.         int i;
  211.         LONG slen;
  212.  
  213.         _fmemcpy(&ebuf, asb, (int) ((sizeof(struct soundbuf) - BUFL) + lts));
  214.         slen = lts;
  215.  
  216.         /* DES encryption. */
  217.  
  218.         if (d->deskey[0]) {
  219.             char twibble[8];
  220.             
  221.             _fmemcpy(twibble, d->deskey + 1, 8);
  222.             setkey(twibble);
  223.  
  224.             /* If we're DES encrypting we must round the size of
  225.                the data to be sent to be a multiple of 8 so that
  226.                the entire DES frame is sent. */
  227.  
  228.             slen = (slen + 7) & (~7);
  229.             for (i = 0; i < slen; i += 8) {
  230.  
  231.                 /* Apply cipher block chaining within the packet. */
  232.  
  233.                 if (i > 0) {
  234.                     int j;
  235.  
  236.                     for (j = 0; j < 8; j++) {
  237.                         ebuf.buffer.buffer_val[(i + j)] ^=
  238.                             ebuf.buffer.buffer_val[(i + j) - 8];
  239.                     }
  240.                 }
  241.                 endes(ebuf.buffer.buffer_val + i);
  242.             }
  243.             ebuf.compression |= fEncDES;
  244.         }
  245.  
  246.         /* IDEA encryption. */
  247.  
  248.         if (d->ideakey[0]) {
  249.             unsigned short iv[4];
  250.             char twibble[16];
  251.             
  252.             _fmemcpy(twibble, d->ideakey + 1, 16);
  253.             memset(iv, 0, sizeof(iv));
  254.             initcfb_idea(iv, twibble, FALSE);
  255.  
  256.             /* If we're IDEA encrypting we must round the size of
  257.                the data to be sent to be a multiple of 8 so that
  258.                the entire IDEA frame is sent. */
  259.  
  260.             slen = (slen + 7) & (~7); 
  261.             ideacfb(ebuf.buffer.buffer_val, (int) slen);
  262.             close_idea();
  263.             ebuf.compression |= fEncIDEA;
  264.         }
  265.  
  266.         /* PGP session key encryption. */
  267.  
  268.         if (d->opgpkey[0]) {
  269.             unsigned short iv[4];
  270.             char twibble[16];
  271.             
  272.             _fmemcpy(twibble, d->opgpkey + 1, 16);
  273.             memset(iv, 0, sizeof(iv));
  274.             initcfb_idea(iv, twibble, FALSE);
  275.  
  276.             /* If we're IDEA encrypting we must round the size of
  277.                the data to be sent to be a multiple of 8 so that
  278.                the entire IDEA frame is sent. */
  279.  
  280.             slen = (slen + 7) & (~7); 
  281.             ideacfb(ebuf.buffer.buffer_val, (int) slen);
  282.             close_idea();
  283.             ebuf.compression |= fEncPGP;
  284.         }
  285.  
  286.         /* One-time pad encryption. */
  287.  
  288.         if (d->otpFileName[0]) {
  289.             for (i = 0; i < slen; i++) {
  290.                 ebuf.buffer.buffer_val[i] ^= d->otp[i];
  291.             }
  292.             ebuf.compression |= fEncOTP;
  293.         }
  294.         revlong(&ebuf.compression);
  295.         revlong(&ebuf.buffer.buffer_len);
  296.  
  297.         if (writeOutput(d, (LPSTR) &ebuf,
  298.                 (int) ((sizeof(struct soundbuf) - BUFL) + slen)) < 0) {
  299.             d->state = d->wantsInput ? SendingLiveAudio : Idle;
  300.             if (d->hFile != HFILE_ERROR) {
  301.                 KillTimer(hwnd, 2);
  302.                 _lclose(d->hFile);
  303.                 d->hFile = HFILE_ERROR;
  304.             }
  305.             socketerrorbox(hwnd, d);
  306.             return FALSE;
  307.         }
  308.     } else {
  309.         int stat;
  310.         
  311.         revlong(&asb->compression);
  312.         revlong(&asb->buffer.buffer_len);
  313.         stat = writeOutput(d, (LPSTR) asb,
  314.             (int) ((sizeof(struct soundbuf) - BUFL) + lts));
  315.         revlong(&asb->compression);
  316.         revlong(&asb->buffer.buffer_len);
  317.         if (stat < 0) {
  318.             d->state = d->wantsInput ? SendingLiveAudio : Idle;
  319.             d->wantsInput = FALSE;
  320.             if (d->hFile != HFILE_ERROR) {
  321.                 KillTimer(hwnd, 2);
  322.                 _lclose(d->hFile);
  323.                 d->hFile = HFILE_ERROR;
  324.             }
  325.             socketerrorbox(hwnd, d);
  326.             return FALSE;
  327.         }
  328.     }
  329.     return TRUE;
  330. }
  331.  
  332. /*  SHIPSOUNDBUFFER  --  Output sound buffer to connection.  */
  333.  
  334. void shipSoundBuffer(HWND hwnd, LPCLIENT_DATA pClientData)
  335. {
  336.     sb.compression = pClientData->ring ? (fSetDest | fDestSpkr) : 0;
  337.     pClientData->ring = FALSE;
  338.     sb.compression |= pClientData->debugging ? fDebug : 0;
  339.     sb.compression |= pClientData->loopback ? fLoopBack : 0;
  340.     sb.compression |= compression ? fComp2X : 0;
  341.     sb.compression |= gsmcompress ? fCompGSM : 0;
  342.     sb.compression |= adpcmcompress ? fCompADPCM : 0;
  343.     sb.compression |= lpccompress ? fCompLPC : 0;
  344.     sb.compression |= (faceFile != HFILE_ERROR) ? fFaceOffer : 0;
  345.     
  346.     sendpkt(hwnd, pClientData, &sb);
  347. }
  348.  
  349. /*  CREATESOUNDBUFFER  --  Create a standard format sound buffer
  350.                            with selected compression modes from a
  351.                            set of raw samples received from the audio
  352.                            input port.  */
  353.                         
  354. void createSoundBuffer(LPSTR buffer, WORD buflen, DWORD channels,
  355.                        DWORD rate, DWORD bytesec, WORD align)
  356. {
  357.     int knownFormat = FALSE;
  358.     
  359.     if (rate == 8000) {
  360.         if (align == 2) {
  361.             LONG i;
  362.             int j;
  363.             
  364.             for (i = j = 0; i < (LONG) buflen / align; i++) {
  365.                 sb.buffer.buffer_val[j++] = audio_s2u((((WORD FAR *) buffer)[i]));
  366.             } 
  367.         } else {    // align == 1
  368.             LONG i;
  369.             int j;
  370.             
  371.             for (i = j = 0; i < (LONG) buflen; i++) {
  372.                 sb.buffer.buffer_val[j++] = audio_c2u((((BYTE FAR *) buffer)[i]));
  373.             } 
  374.         }
  375.         sb.buffer.buffer_len = buflen / align;
  376.         knownFormat = TRUE;
  377.     } else if (rate == 11025 && align == 2) {
  378.         LONG i;
  379.         int j, k;
  380.         
  381.         for (i = j = k = 0; i < (LONG) (buflen / align); i++) {
  382.             if ((k & 3) != 2  && ((i % 580) != 579)) {
  383.                 sb.buffer.buffer_val[j++] = audio_s2u((((WORD FAR *) buffer)[i]));
  384.             }
  385.             k = (k + 1) % 11;
  386.         } 
  387.         sb.buffer.buffer_len = j;
  388.         knownFormat = TRUE;
  389.     } else if (rate == 11025 && align == 1) {
  390.         LONG i;
  391.         int j, k;
  392.         
  393.         for (i = j = k = 0; i < (LONG) (buflen / align); i++) {
  394.             if ((k & 3) != 2  && ((i % 580) != 579)) {
  395.                 sb.buffer.buffer_val[j++] = audio_c2u((((BYTE FAR *) buffer)[i]));
  396.             }
  397.             k = (k + 1) % 11;
  398.         } 
  399.         sb.buffer.buffer_len = j;
  400.         knownFormat = TRUE;
  401.     }
  402.     
  403.     if (knownFormat) {
  404.         if (compression) {
  405.             compress2X(&sb);
  406.         }
  407.     
  408.         if (gsmcompress) {
  409.             gsmcomp(&sb);
  410.         }
  411.  
  412.         if (adpcmcompress) {
  413.             adpcmcomp(&sb);
  414.         }
  415.  
  416.         if (lpccompress) {
  417.             lpccomp(&sb);
  418.         }
  419.     }
  420. }                                            
  421.  
  422. /*  CREATENEWCONNECTION  --  Create a new connection MDI window.  */
  423.  
  424. HWND createNewConnection(LPCLIENT_DATA pClientData)
  425. {
  426.     MDICREATESTRUCT mcs;
  427.     HWND hwnd;
  428.     SOCKERR serr = 0;
  429.  
  430. #ifdef TRACE_FACE
  431.         OutputDebugString("createNewConnection()\r\n");
  432. #endif
  433.     mcs.szClass = pszClientClass;
  434.     mcs.szTitle = pClientData->szHost,
  435.     mcs.hOwner = hInst;
  436.     mcs.x = CW_USEDEFAULT;
  437.     mcs.y = CW_USEDEFAULT;
  438.     mcs.cx = tmAveCharWidth * 30;
  439.     mcs.cy = tmHeight * 5;
  440.     mcs.style = 0;
  441.  
  442.     hwnd = FORWARD_WM_MDICREATE(hwndMDIClient, (LPMDICREATESTRUCT) &mcs, SendMessage);
  443.  
  444.     if (hwnd == NULL) {
  445.         return NULL;
  446.     }
  447.     
  448.     pClientData->state = Idle;
  449.     SetWindowLong(hwnd, GWL_CLIENT, (LONG) pClientData);
  450.     if (!pClientData->modemConnection) {
  451.         serr = CreateSocket(&(pClientData->sReply), SOCK_DGRAM,
  452.                              htonl(INADDR_ANY), 0);
  453.     
  454.         if (serr == 0) {
  455.             pClientData->name.sin_family = PF_INET;
  456.             pClientData->name.sin_addr = pClientData->inetSock.sin_addr;
  457.             pClientData->name.sin_port = htons(NETFONE_COMMAND_PORT);
  458.             
  459.             if (!waNetNoConnect) {
  460.                 if (connect(pClientData->sReply, (LPSOCKADDR) &(pClientData->name),
  461.                      sizeof(pClientData->name)) != 0) {
  462.                     serr = WSAGetLastError();
  463.                 }
  464.             }
  465. #ifdef ASYNC_OUTPUT            
  466.             if (serr == 0) {
  467.                 serr = WSAAsyncSelect(pClientData->sReply, hwnd, WM_SOCKET_SELECT,
  468.                                 FD_WRITE);
  469.              }
  470. #endif             
  471.            }
  472.         if (serr != 0) {
  473.            MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(23),
  474.                     (LPSTR) pClientData->szHost, serr, SockerrToString(serr));
  475.             return NULL;
  476.         }
  477.     }
  478.  
  479.     pClientData->gsmh = gsm_create();
  480.     
  481.     /* Since the sending buffer is static, there's no reason
  482.        to get the host name for every packet (like, it doesn't
  483.        change, right?).  So just get it when we initialise a new
  484.        connection.  The nonsense with "gh" is because some WINSOCK
  485.        implementations fail if the host buffer is too small, as
  486.        opposed to truncating the name as Unix does. */
  487.     
  488.     {
  489.         char gh[MAX_HOST];
  490.         
  491.         gethostname(gh, sizeof gh);
  492.         if (strlen(gh) > ((sizeof sb.sendinghost) - 1)) {
  493.             gh[(sizeof sb.sendinghost) - 1] = 0;
  494.         }
  495.         strcpy(sb.sendinghost, gh);
  496.     }
  497.     
  498.     if (pClientData->modemConnection) {
  499.         SetWindowText(hwnd, rstring(IDS_T_MODEM_CONNECTION));
  500.         modemSessions++;
  501.     } else if (pClientData->szHost[0] == '(') {
  502.         /* This is a temporary connection initiated from the remote site.
  503.            Schedule a lookup to obtain the full domain name of the host,
  504.            not just the hostname included in the sound packet. */
  505.         pClientData->getNameTask = WSAAsyncGetHostByAddr(hwnd, WM_SOCKET_ASYNC,
  506.                                         (CHAR FAR *) &pClientData->inetSock.sin_addr,
  507.                                         sizeof(pClientData->inetSock.sin_addr),
  508.                                         PF_INET, pClientData->hostBuffer,
  509.                                         sizeof(pClientData->hostBuffer));
  510.         if (pClientData->getNameTask == NULL) {
  511.             int serr = WSAGetLastError();
  512.             MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(24),
  513.                     (LPSTR) pClientData->szHost, serr, SockerrToString(serr));
  514.         }                                 
  515.     }
  516.  
  517.     DragAcceptFiles(hwnd, TRUE);
  518.     ShowWindow(hwnd, SW_SHOW);
  519.     openConnections++;
  520.     propUpdateAudio();
  521.  
  522.     return hwnd;
  523. }
  524.  
  525. //    CONNFETCHFACE  --  Begin retrieval of a face image.
  526.  
  527. void connFetchFace(HWND hwndClient, LPCLIENT_DATA pClientData)
  528. {
  529. //    pClientData->face_stat = FSabandoned;
  530. //    if (pClientData->face_stat != -1) {
  531. #ifdef TRACE_FACE
  532.         OutputDebugString("connFetchFace()\r\n");
  533. #endif
  534.         pClientData->face_address = 0L;
  535.         pClientData->face_timeout = 0;
  536.         pClientData->face_retry = 0;
  537.         pClientData->face_stat = FSreply;       // Activate request from timeout
  538.         SetTimer(hwndClient, 5, (UINT) FaceFetchInterval, NULL);
  539. //    }
  540. }
  541.  
  542. //    STARTSOUNDFILE  --  Begin playing a sound file.
  543.  
  544. VOID startSoundFile(HWND hwnd, LPSTR pszFile)
  545. {
  546.     LPCLIENT_DATA pClientData;
  547.     HFILE hFile = HFILE_ERROR;
  548.     char magic[4];
  549.  
  550.     pClientData = CLIENTPTR(hwnd);
  551.     
  552.     pClientData->quitSoundFile = FALSE;
  553.     pClientData->hFile = HFILE_ERROR;
  554.     if (pClientData->timeout > 0) {
  555.         pClientData->timeout = 0;
  556.     }
  557.     pClientData->cbSent = 0L;
  558.  
  559.     //  Try to open it
  560.  
  561.     hFile = _lopen(pszFile, OF_READ | OF_SHARE_DENY_WRITE);
  562.  
  563.     if (hFile == HFILE_ERROR) {
  564.         //  Error opening file
  565.  
  566.         MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(25),
  567.                 pszFile, (LPSTR) pClientData->szHost);
  568.         goto FatalError;
  569.     }
  570.     _lread(hFile, magic, sizeof(long));
  571.     
  572.     /* See if it's a chunky, wavy RIFF.  If so, delegate
  573.        handling of the file to the multimedia I/O package. */
  574.        
  575.     if (memcmp(magic, "RIFF", 4) == 0) {
  576.         _lclose(hFile);
  577.         if (!readWaveInit(hwnd, pClientData, pszFile)) {
  578.             return;
  579.         }
  580.     } else {
  581.     
  582.         /* If the file has a Sun .au file header, skip it.
  583.            Note that we still blithely assume the file is
  584.            8-bit ISDN u-law encoded at 8000 samples per
  585.            second. */
  586.     
  587.         if (memcmp(magic, ".snd", 4) == 0) {
  588.             long startpos;
  589.     
  590.             _lread(hFile, &startpos, sizeof(long));
  591.             revlong(&startpos);
  592.             _llseek(hFile, startpos, 0);
  593.         } else {
  594.             _llseek(hFile, 0L, 0);
  595.         }
  596.         pClientData->hFile = hFile;
  597.     }
  598.     
  599.     pClientData->state = Transferring;
  600.     if (pClientData->timeout > 0) {
  601.         pClientData->timeout = 0;
  602.     }
  603.  
  604. #ifdef SHOW_STATE
  605.     InvalidateRect(hwnd, NULL, TRUE);
  606.     UpdateWindow(hwnd);
  607. #endif    
  608.     DragAcceptFiles(hwnd, FALSE);
  609.     if (SetTimer(hwnd, 2, 200, NULL) == 0) {
  610.         MsgBox(NULL, MB_ICONSTOP | MB_OK, Format(26));
  611.     }
  612.     return;
  613.  
  614. FatalError:
  615.     if (hFile != HFILE_ERROR) {
  616.         _lclose(hFile);
  617.     }
  618. }
  619.  
  620. /*  FILEDROPPED  --  Handle file dropped in connection window.  */
  621.  
  622. static VOID fileDropped(HWND hwnd, HDROP hdrop)
  623. {
  624.     LPCLIENT_DATA pClientData;
  625.     
  626.     pClientData = CLIENTPTR(hwnd);
  627.  
  628.     //  Retrieve the dropped file
  629.  
  630.     DragQueryFile(hdrop, 0, pClientData->szFile, sizeof(pClientData->szFile));
  631.     DragFinish(hdrop);
  632.     
  633.     //    Start output
  634.     
  635.     startSoundFile(hwnd, pClientData->szFile); 
  636. }
  637.  
  638. /*  STATETOSTRING  --  Convert state value to string.  */
  639.  
  640. static LPSTR stateToString(CLIENT_STATE state)
  641. {
  642.     LPSTR pszResult;
  643.  
  644.     switch (state) {
  645.         case Embryonic:
  646.             pszResult = rstring(IDS_T_INITIALISING);
  647.             break;
  648.     
  649.         case Idle:
  650.             pszResult = rstring(IDS_T_IDLE);
  651.             break;
  652.     
  653.         case SendingLiveAudio:
  654.             pszResult = rstring(IDS_T_SENDING_LIVE);
  655.             break;
  656.     
  657.         case Transferring:
  658.             pszResult = rstring(IDS_T_SENDING_FILE);
  659.             break;
  660.     
  661.         case PlayingReceivedAudio:
  662.             pszResult = rstring(IDS_T_PLAYING_AUDIO);
  663.             break;
  664.     
  665.         default:
  666.             pszResult = rstring(IDS_T_UNKNOWN);
  667.             break;
  668.     }
  669.     return pszResult;
  670. }
  671.  
  672. /*    CHANGEAUDIOSTATE  --  Change transmitting / receiving state.  */
  673.  
  674. static void changeAudioState(HWND hwnd, LPCLIENT_DATA pClientData)
  675. {
  676.     if (pClientData->face_shown) {
  677.         LPSTR hname = pClientData->modemConnection ?
  678.                 rstring(IDS_T_MODEM_CONNECTION) : pClientData->szHost;
  679.         if (pClientData->wantsInput) {
  680.             char s[MAX_HOST + 20];
  681.             
  682.             strcpy(s, "==> ");
  683.             _fstrcat(s, hname);
  684.             SetWindowText(hwnd, s); 
  685.         } else {
  686.             SetWindowText(hwnd, hname);
  687.         } 
  688.     } else {
  689.         InvalidateRect(hwnd, NULL, TRUE);
  690.         UpdateWindow(hwnd);
  691.     }
  692. }
  693.  
  694. /*  DESTROYCONNECTION  --  Destroy connection, cleaning up debris
  695.                            and releasing resources.  */
  696.  
  697. static VOID destroyConnection(HWND hwnd, LPCLIENT_DATA pClientData)
  698. {
  699.     if (pClientData->sReply != INVALID_SOCKET) {
  700.         ResetSocket(pClientData->sReply);
  701.         pClientData->sReply = INVALID_SOCKET;
  702.     }
  703.  
  704.     if (pClientData->hFile != HFILE_ERROR) {
  705.         _lclose(pClientData->hFile);
  706.         pClientData->hFile = HFILE_ERROR;
  707.     }
  708.  
  709.     pClientData->state = Idle;
  710.  
  711.     if (hwnd != NULL) {
  712. #ifdef SHOW_STATE
  713.         InvalidateRect(hwnd, NULL, TRUE);
  714.         UpdateWindow(hwnd);
  715. #endif        
  716.         DragAcceptFiles(hwnd, TRUE);
  717.     }
  718. }
  719.  
  720. /*  CONNECT_WNDPROC  --  Connection main window procedure.  */
  721.  
  722. LRESULT CALLBACK connectWndProc(HWND hwnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
  723. {
  724.     LPCLIENT_DATA pClientData;
  725.  
  726.     pClientData = CLIENTPTR(hwnd);
  727.     
  728.     switch (nMessage) {
  729.     
  730. //        case WM_MDIACTIVATE:
  731. //            if (wParam) {
  732. //                InvalidateRect(hwnd, NULL, FALSE);
  733. //                UpdateWindow(hwnd);
  734. //            }
  735. //            break;
  736.     
  737.         case WM_CHAR:
  738.             if (wParam == ' ') {
  739.                 if (pClientData != NULL) {
  740.                     if (!pClientData->wantsInput) {
  741.                         goto spacebarOn;
  742.                     } else {
  743.                         goto spacebarOff;
  744.                     }
  745.                 }    
  746.             }
  747.             return 0;
  748.         
  749.         case WM_CLOSE:
  750.             if (pClientData != NULL) {
  751.                 destroyConnection(NULL, pClientData);
  752.             }
  753.             FORWARD_WM_CLOSE(hwnd, DefMDIChildProc);
  754.             return 0;
  755.             
  756.         case WM_CREATE:
  757. #ifdef TRACE_FACE
  758.             OutputDebugString("Connection WM_CREATE()\r\n");
  759. #endif
  760.             SetFocus(hwnd);
  761.             break;
  762.         
  763.         case WM_DESTROY:
  764.             if (pClientData != NULL) {
  765.                 if (pClientData->wantsInput && --listeners <= 0) {
  766.                     terminateWaveInput();
  767.                     listeners = 0;
  768.                 }
  769.                 gsm_destroy(pClientData->gsmh);
  770.                 if (pClientData->hFile != HFILE_ERROR ||
  771.                     pClientData->mmioHandle != NULL) {
  772.                     KillTimer(hwnd, 2);
  773.                     if (pClientData->hFile != HFILE_ERROR) {
  774.                         _lclose(pClientData->hFile);
  775.                     }
  776.                     readWaveTerm(pClientData);
  777.                 }
  778.                 
  779.                 if (pClientData->pgpFileName[0] != 0) {
  780.                     KillTimer(hwnd, 3);                // Kill timer for incomplete PGP poll
  781.                     // T'would be nice to clean up the temp files here as well.
  782.                 }
  783.                 
  784.                 if (pClientData->opgpFileName[0] != 0) {
  785.                     KillTimer(hwnd, 4);                // Kill timer for incomplete PGP poll
  786.                     // T'would be nice to clean up the temp files here as well.
  787.                 }
  788.                 
  789.                 if (pClientData->face_stat == FSrequest ||
  790.                     pClientData->face_stat == FSreply) {
  791.                     KillTimer(hwnd, 5);                // Kill timer for incomplete face image
  792.                 }
  793.                 if (pClientData->face_bmp != NULL) {
  794.                     GlobalFreePtr(pClientData->face_bmp);    // Release face bitmap
  795.                 }
  796.  
  797.                 if (pClientData->modemConnection) {
  798.                     modemSessions--;
  799.                 }
  800.                 
  801.                 if (pClientData->getNameTask != NULL) {
  802.                     WSACancelAsyncRequest(pClientData->getNameTask);
  803.                     pClientData->getNameTask = NULL;    
  804.                 }
  805.                 
  806.                 GlobalFreePtr(pClientData);
  807.                 SetWindowLong(hwnd, GWL_CLIENT, 0L);
  808.             } 
  809.             openConnections--;
  810.             propUpdateAudio();
  811.             return 0;
  812.             
  813.         case WM_DROPFILES:
  814.             if (pClientData != NULL && !broadcasting) {
  815.                 pClientData->timeout = -1;    // Send file immortalises connection
  816.                 fileDropped(hwnd, (HDROP) wParam);
  817.             }
  818.             break;
  819.  
  820. #ifdef GATES_OF_HELL
  821.  
  822.         /* Well, golly, I though it would be kinda nice to keep
  823.            the user from inflating the connection window larger than
  824.            the face image in it--doing so only wastes screen
  825.            real estate, after all.  Little did I know that by trying
  826.            to do so (at least with an MDI window), I stuck my toe
  827.            back into the tree chipper and caused all kinds of
  828.            things to let go--window size changing when iconised
  829.            and reactivated, the "disappearing minimise button
  830.            syndrome", etc. etc.  The Developer CD serves up the
  831.            usual crop of incoherent blithering.  I give up--go
  832.            ahead and make the bloody window as big as Siberia
  833.            if you like. */
  834.             
  835.         case WM_GETMINMAXINFO:
  836.             if (pClientData != NULL && pClientData->face_shown) {
  837.                 MINMAXINFO FAR *mm = (MINMAXINFO FAR *) lParam;
  838.                 BITMAPINFOHEADER FAR *bmi;
  839.                 RECT cr, wr;
  840.                         
  841.                 GetWindowRect(hwnd, &wr);
  842.                 GetClientRect(hwnd, &cr);
  843.                             
  844.                 bmi = (BITMAPINFOHEADER FAR *) (pClientData->face_bmp + sizeof(BITMAPFILEHEADER));
  845.                 
  846.                 //    Don't allow resize of window larger than face
  847.  
  848.                 mm->ptMaxSize.x = mm->ptMaxTrackSize.x = ((int) bmi->biWidth) + ((wr.right - wr.left) - cr.right); 
  849.                 mm->ptMaxSize.x = mm->ptMaxTrackSize.y = ((int) bmi->biHeight) + ((wr.bottom - wr.top) - cr.bottom); 
  850.             } 
  851.             break;
  852. #endif            
  853.             
  854.         case WM_LBUTTONDBLCLK:
  855.         case WM_LBUTTONDOWN:
  856. spacebarOn: if (pClientData != NULL && !pClientData->wantsInput && !broadcasting) {
  857.                 if (listeners == 0) {
  858.                     if (!startWaveInput(hwnd)) {
  859.                         //    Couldn't turn on wave audio input
  860.                         break;
  861.                     }
  862.                 }
  863.                 pClientData->wantsInput = (nMessage == WM_LBUTTONDBLCLK) ? 2 : TRUE;
  864.                 listeners++;
  865.                 pClientData->timeout = -1;    // Send audio immortalises connection
  866.                 pClientData->state = SendingLiveAudio;
  867.                 SetCursor(earCursor);
  868.                 changeAudioState(hwnd, pClientData);
  869.             }
  870.             break;
  871.             
  872.         case WM_LBUTTONUP:
  873. spacebarOff:if (pClientData != NULL && !broadcasting) {
  874.                 if (pClientData->wantsInput == TRUE) {
  875.                     pClientData->wantsInput = FALSE;
  876.                     pClientData->state = pClientData->hFile != HFILE_ERROR ?
  877.                         Transferring : Idle;
  878.                     SetCursor(phoneCursor);
  879.                     changeAudioState(hwnd, pClientData);
  880.                     if (--listeners <= 0) {
  881.                         terminateWaveInput();
  882.                         listeners = 0;
  883.                     }
  884.                 /* If this the button-up following a double click, don't
  885.                    turn off listening.  This allows a double click to latch
  886.                    input mode for a window. */
  887.                 } else if (pClientData->wantsInput == 2) {
  888.                     pClientData->wantsInput = TRUE;
  889.                     SetCursor(earCursor);
  890.                     UpdateWindow(hwnd);
  891.                 }
  892.             } 
  893.             break;
  894.             
  895.         case WM_MOUSEMOVE:
  896.             if (pClientData != NULL) {
  897.                 SetCursor((pClientData->wantsInput || broadcasting) ? earCursor :
  898.                             phoneCursor);
  899.             }
  900.             break;
  901.         
  902.         case WM_PAINT:
  903.             {
  904. #define DCOL    11            
  905.                 PAINTSTRUCT psPaint;
  906.                 HDC hdc;
  907.                 HBITMAP ibmap = NULL;
  908.                 int active = hwnd == ((HWND) LOWORD(SendMessage(hwndMDIClient, WM_MDIGETACTIVE, 0, 0L)));
  909.  
  910.                 hdc = BeginPaint(hwnd, &psPaint);
  911.                 if (pClientData != NULL) {
  912.                     if (pClientData->face_stat == FScomplete &&
  913.                         pClientData->face_bmp != NULL) {
  914.                         int bx, by;
  915.                         RECT cr, wr;
  916.                         BITMAPFILEHEADER FAR *bfh;
  917.                         BITMAPINFOHEADER FAR *bmi;
  918.                         char _huge *bits;
  919.                         HPALETTE bpal = NULL, opal;
  920.                         int i;
  921.                         LPLOGPALETTE lp;
  922.                         BITMAPINFO FAR *bh;
  923.                         unsigned short FAR *palidx;
  924.                         LPSTR lpalette;
  925.                         unsigned short FAR *savepal;
  926. #ifdef TRACE_FACE
  927. {    char s[256];
  928.                         
  929.     wsprintf(s, "Paint %04X: %s\r\n", hwnd, pClientData->szHost);
  930.     OutputDebugString(s);
  931. }
  932. #endif                        
  933.                         
  934.                         pClientData->face_shown = FALSE;
  935.                         savepal = (unsigned short FAR *) GlobalAllocPtr(GPTR,
  936.                                     sizeof(LOGPALETTE) +
  937.                                     sizeof(PALETTEENTRY) * 256 +
  938.                                     sizeof(short) * 256);
  939.                         if (savepal == NULL) {
  940.                             goto face_failed;
  941.                         }
  942.                         lpalette = ((LPSTR) savepal) + 256 * sizeof(short); 
  943.                         GetWindowRect(hwnd, &wr);
  944.                         GetClientRect(hwnd, &cr);
  945.                         
  946.                         bfh = (BITMAPFILEHEADER FAR *) pClientData->face_bmp;
  947.                         bmi = (BITMAPINFOHEADER FAR *) (pClientData->face_bmp + sizeof(BITMAPFILEHEADER));
  948.                         bh = (BITMAPINFO FAR *) bmi; 
  949.                         bx = (int) bmi->biWidth;
  950.                         by = (int) bmi->biHeight;
  951.                         
  952.                         if (bmi->biClrUsed == 0) {
  953.                             bmi->biClrUsed = 1L << bmi->biBitCount;
  954.                         }
  955.  
  956.                         bits = (char FAR *) (pClientData->face_bmp + bfh->bfOffBits);
  957.  
  958.                         lp = (LOGPALETTE FAR *) lpalette;
  959.                         palidx = (unsigned short FAR *) bh->bmiColors;
  960.                         _fmemcpy(savepal, palidx, 256 * sizeof(short));
  961.                         lp->palVersion = 0x0300;
  962.                         lp->palNumEntries = (WORD) bmi->biClrUsed;
  963.                         for (i = 0; i < ((int) bmi->biClrUsed); i++) {
  964.                             lp->palPalEntry[i].peRed = bh->bmiColors[i].rgbRed;
  965.                             lp->palPalEntry[i].peGreen = bh->bmiColors[i].rgbGreen;
  966.                             lp->palPalEntry[i].peBlue = bh->bmiColors[i].rgbBlue;
  967.                             lp->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
  968.                             if (active) {
  969. //                                palidx[i] = (unsigned short) i;
  970.                             }
  971.                         }
  972.                         bpal = CreatePalette(lp);
  973.                         if (active && bpal != NULL) {
  974.                             opal = SelectPalette(hdc, bpal, FALSE);
  975.                             RealizePalette(hdc);
  976.                         }
  977.  
  978.                         ibmap = CreateDIBitmap(hdc, bmi, CBM_INIT,
  979.                                     bits, (BITMAPINFO FAR *) bmi, DIB_RGB_COLORS);
  980.                         _fmemcpy(palidx, savepal, 256 * sizeof(short));
  981.                         if (ibmap != NULL) {
  982.                             HDC hMemDC;
  983.                             HBITMAP obmap;
  984.                             HPALETTE mopal;
  985.         
  986.                             hMemDC = CreateCompatibleDC(hdc);
  987.                             if (bpal != NULL) {
  988.                                 mopal = SelectPalette(hMemDC, bpal, FALSE);
  989.                             }
  990.                             obmap = SelectObject(hMemDC, ibmap);
  991.                             if (bx <= cr.right && by <= cr.bottom) {
  992.                                 BitBlt(hdc, (cr.right - bx) / 2, (cr.bottom - by) / 2,
  993.                                     bx, by, hMemDC, 0, 0, SRCCOPY);
  994.                             } else {
  995.                                 int nx, ny;
  996.                                 double xshrink = ((double) bx) / cr.right,
  997.                                        yshrink = ((double) by) / cr.bottom;
  998.         
  999. #ifdef TRACE_FACE
  1000.                                 OutputDebugString("Yick!!!  Had to stretch face bitmap.\r\n");
  1001. #endif
  1002.                                 if (xshrink > yshrink) {
  1003.                                     nx = cr.right;
  1004.                                     ny = (int) (by / xshrink);
  1005.                                 } else {
  1006.                                     ny = cr.bottom;
  1007.                                     nx = (int) (bx / yshrink);
  1008.                                 }
  1009.                                 SetStretchBltMode(hdc, STRETCH_DELETESCANS);
  1010.                                 StretchBlt(hdc, (cr.right - nx) / 2, (cr.bottom - ny) / 2, nx, ny,
  1011.                                     hMemDC, 0, 0, bx, by, SRCCOPY);
  1012.                             }
  1013.                             SelectObject(hMemDC, obmap);
  1014.                             DeleteObject(ibmap);
  1015.                             if (bpal != NULL) {
  1016.                                 if (active) {
  1017.                                     SelectPalette(hdc, opal, FALSE);
  1018.                                 }
  1019.                                 SelectPalette(hMemDC, mopal, FALSE);
  1020.                                 DeleteObject(bpal);
  1021.                             }
  1022.                             DeleteDC(hMemDC);
  1023.                             pClientData->face_shown = TRUE;
  1024.                         }
  1025.                         GlobalFreePtr(savepal);                        
  1026.                     }
  1027. face_failed:                    
  1028.                     if (!pClientData->face_shown) {
  1029.                         WinPrintf(hdc, 0, 1, pClientData->modemConnection ?
  1030.                             rstring(IDS_T_DIAL_STRING) : rstring(IDS_T_HOST));
  1031.                         WinPrintf(hdc, 0, DCOL, pClientData->szHost);
  1032.                         
  1033.                         if (pClientData->modemConnection) {
  1034.                             WinPrintf(hdc, 1, 1, rstring(IDS_T_MODEM_CONNECTION_L));
  1035.                         } else {
  1036.                             WinPrintf(hdc, 1, 1, rstring(IDS_T_ADDRESS));
  1037.                             WinPrintf(hdc, 1, DCOL, Format(48), inet_ntoa(pClientData->inetSock.sin_addr));
  1038.                         }
  1039.                         
  1040.                         WinPrintf(hdc, 2, 1, pClientData->wantsInput ? rstring(IDS_T_TRANSMITTING) :
  1041.                             rstring(IDS_T_BLANKTRANSMIT));
  1042.     
  1043. #ifdef SHOW_STATE
  1044.                         /* It's nice to show the state, but costly to update on
  1045.                            every packet. */
  1046.                                        
  1047.                         WinPrintf(hdc, 3, 1, "State:");
  1048.                         WinPrintf(hdc, 3, DCOL, "%s", stateToString(pClientData->state));
  1049.                 
  1050.                         switch (pClientData->state) {
  1051.                             case Idle:
  1052.                                 WinPrintf(hdc, 4, 1, blankit);
  1053.                                 WinPrintf(hdc, 5, 1, blankit);
  1054.                                 break;
  1055.                                 
  1056.                             case Transferring:
  1057.                                 WinPrintf(hdc, 4, 1, "File: ");
  1058.                                 WinPrintf(hdc, 4, DCOL, "%s", pClientData->szFile);
  1059.                                 WinPrintf(hdc, 5, 1, "Bytes sent:");
  1060.                                 WinPrintf(hdc, 5, DCOL, "%lu", pClientData->cbSent);
  1061.                                 break;
  1062.                                 
  1063.                             case PlayingReceivedAudio:
  1064.                                 WinPrintf(hdc, 4, 1, "Bytes received:");
  1065.                                 WinPrintf(hdc, 4, DCOL, "%lu", pClientData->cbReceived);
  1066.                                 break;                            
  1067.                         }
  1068. #endif                    
  1069.                     }
  1070. #undef DCOL
  1071.                 }                
  1072.             
  1073.                 EndPaint(hwnd, &psPaint);            
  1074.             }
  1075.             break;
  1076.             
  1077. case WM_MDIACTIVATE:
  1078.             if (wParam == FALSE || IsIconic(hwnd)) {
  1079.                 break;
  1080.             }
  1081.             if (pClientData != NULL && pClientData->face_shown) {
  1082.                 HDC hdc;
  1083.                 BITMAPINFOHEADER FAR *bmi;
  1084.                 HPALETTE bpal = NULL, opal;
  1085.                 int i;
  1086.                 LPLOGPALETTE lp;
  1087.                 BITMAPINFO FAR *bh;
  1088.                 LPSTR lpalette;
  1089. #ifdef TRACE_FACE
  1090. {    char s[256];
  1091.                         
  1092.     wsprintf(s, "MDI activate %04X: %s\r\n", hwnd, pClientData->szHost);
  1093.     OutputDebugString(s);
  1094. }
  1095. #endif                        
  1096.                         
  1097.                 lpalette =  GlobalAllocPtr(GPTR, sizeof(LOGPALETTE) +
  1098.                             sizeof(PALETTEENTRY) * 256);
  1099.                 if (lpalette != NULL) {
  1100.                     bmi = (BITMAPINFOHEADER FAR *) (pClientData->face_bmp + sizeof(BITMAPFILEHEADER));
  1101.                     bh = (BITMAPINFO FAR *) bmi; 
  1102.                     lp = (LOGPALETTE FAR *) lpalette;
  1103.                     lp->palVersion = 0x0300;
  1104.                     lp->palNumEntries = (WORD) bmi->biClrUsed;
  1105.                     for (i = 0; i < ((int) bmi->biClrUsed); i++) {
  1106.                         lp->palPalEntry[i].peRed = bh->bmiColors[i].rgbRed;
  1107.                         lp->palPalEntry[i].peGreen = bh->bmiColors[i].rgbGreen;
  1108.                         lp->palPalEntry[i].peBlue = bh->bmiColors[i].rgbBlue;
  1109.                         lp->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
  1110.                     }
  1111.                     bpal = CreatePalette(lp);
  1112.                     if (bpal != NULL) {
  1113.                            hdc = GetDC(hwnd);
  1114.                         opal = SelectPalette(hdc, bpal, FALSE);
  1115.                         i = RealizePalette(hdc);
  1116.                         SelectPalette(hdc, opal, FALSE);
  1117.                         DeleteObject(bpal);                        
  1118.                         ReleaseDC(hwnd, hdc);
  1119.                         if (i > 0) {
  1120.                             HWND oldwin;
  1121.                             
  1122.                             InvalidateRect(hwnd, NULL, TRUE);
  1123.                             UpdateWindow(hwnd);
  1124.                             oldwin = (HWND) HIWORD(lParam);
  1125.                             if (oldwin != NULL) {
  1126.                                 InvalidateRect(oldwin, NULL, TRUE);
  1127.                                 UpdateWindow(oldwin);
  1128.                             }
  1129.                         }
  1130.                         return i;
  1131.                     }
  1132.                     GlobalFreePtr(lpalette);
  1133.                 }
  1134.             }
  1135.             break;
  1136.  
  1137. #ifdef ASYNC_OUTPUT            
  1138.         case WM_SOCKET_SELECT:
  1139.             if (pClientData != NULL) {
  1140.                 pClientData->outputSocketBusy = FALSE;
  1141.             }
  1142.             return 0;
  1143. #endif            
  1144.             
  1145.         case WM_SOCKET_ASYNC:
  1146.             if (pClientData != NULL) {
  1147.                    if (WSAGETASYNCERROR(lParam) == 0) {
  1148.                     LPHOSTENT host;
  1149.                 
  1150.                     pClientData->getNameTask = NULL;
  1151.                     host = (LPHOSTENT) pClientData->hostBuffer;
  1152.                     SetWindowText(hwnd, host->h_name);
  1153.                     _fstrcpy(pClientData->szHost, host->h_name);
  1154.                     changeAudioState(hwnd, pClientData);
  1155.                 } else {
  1156.                    MsgBox(hwnd, MB_ICONSTOP | MB_OK, Format(27),
  1157.                             pClientData->szHost, WSAGETASYNCERROR(lParam),
  1158.                             SockerrToString(WSAGETASYNCERROR(lParam)));
  1159.                 }
  1160.             }
  1161.             break;
  1162.                         
  1163.         case WM_TIMER:
  1164.             {
  1165.                 DWORD startTicks = GetTickCount();
  1166.  
  1167.                 if (pClientData == NULL) {
  1168.                      break;
  1169.                 }
  1170.  
  1171.                 /* If there are no buffers pending, advance the timeout
  1172.                    counter.  When it reaches TIMEOUT_CONNECTION, close the
  1173.                    connection. */
  1174.             
  1175.                 if (wParam == FRAME_TIMER_ID && !broadcasting && 
  1176.                     pClientData->timeout >= 0 && outputPending == 0) {
  1177.                     if ((pClientData->timeout++) >= TIMEOUT_CONNECTION) {
  1178.                         FORWARD_WM_MDIDESTROY(hwndMDIClient, hwnd, SendMessage);
  1179.                         return 0;
  1180.                     }
  1181.                     if (pClientData->timeout == 5) {
  1182.                         if (!IsIconic(hwnd)) {
  1183.                             pClientData->cbReceived = 0;
  1184.                             pClientData->state = Idle;
  1185. if (pClientData->face_stat == -1) {
  1186.     pClientData->face_stat = FSinit;    
  1187. }                            
  1188. #ifdef SHOW_STATE                            
  1189.                             InvalidateRect(hwnd, NULL, TRUE);
  1190.                             UpdateWindow(hwnd);
  1191. #endif             
  1192.                         }
  1193.                     }
  1194.                 }
  1195.                 
  1196.                 /* If a broadcast is underway and the site has requested
  1197.                    to unsubscribe, close the connection after a decent
  1198.                    interval has elapsed to avoid toggling due to multiple
  1199.                    packets. */
  1200.                    
  1201.                 if (wParam == FRAME_TIMER_ID && broadcasting &&
  1202.                     pClientData->broadcastEnd &&
  1203.                     ((GetTickCount() - pClientData->broadcastBeginTime) >
  1204.                      (BroadcastUnsubscribe * 1000L))) {
  1205.                     FORWARD_WM_MDIDESTROY(hwndMDIClient, hwnd, SendMessage);
  1206.                     return 0;
  1207.                 }    
  1208.                  
  1209.                 /* Cadence timer indicating it's time to send the
  1210.                    next block of a sound file.  Read it in and send
  1211.                    it on its way. */
  1212.             
  1213.                 if (wParam == 2 && pClientData->hFile != HFILE_ERROR ||
  1214.                                    pClientData->mmioHandle != NULL) {
  1215.                         long et;
  1216.                         UINT bread = 0;
  1217.                         
  1218.                         if (pClientData->modemConnection) {
  1219.                             int err;
  1220.                             COMSTAT cs;
  1221.                             
  1222.                             err = GetCommError(modemHandle, &cs);
  1223.                             if (cs.cbOutQue > 1000) {
  1224.                                 /* If modem connection and modem's backed up
  1225.                                    with output, spin until it goes idle. */
  1226.                                 SetTimer(hwnd, 2, 10, NULL);
  1227.                                 break;
  1228.                             }
  1229.                         }
  1230.                         if (pClientData->mmioHandle != NULL) {
  1231.                             //    Queue next packet from .WAV input file
  1232.                             if (!pClientData->quitSoundFile) {
  1233.                                 bread = readWaveNext(hwnd, pClientData);
  1234.                             }
  1235.                             if (bread == 0) {
  1236.                                 readWaveTerm(pClientData);
  1237.                             } else {
  1238.                                 bread = (UINT) ((bread * 8000L) / 11025L);
  1239.                             } 
  1240.                         } else {
  1241.                             //    Queue next packet from .AU input file
  1242.                             if (!pClientData->quitSoundFile) {
  1243.                                 bread = _lread(pClientData->hFile,
  1244.                                         sb.buffer.buffer_val, currentInputSamples);
  1245.                             }
  1246.                             if (bread == 0) {
  1247.                                 _lclose(pClientData->hFile);
  1248.                                 pClientData->hFile = HFILE_ERROR;
  1249.                             } else {
  1250.                                 sb.buffer.buffer_len = bread;
  1251.                                 /* Since we're manufacturing our own sound buffer
  1252.                                    in place rather than calling CreateSoundBuffer(),
  1253.                                    we need to apply whatever compression is requested
  1254.                                    here before shipping the buffer. */
  1255.                                 if (compression) {
  1256.                                     compress2X(&sb);
  1257.                                 }
  1258.                                 if (gsmcompress) {
  1259.                                     gsmcomp(&sb);
  1260.                                 }
  1261.                                 if (adpcmcompress) {
  1262.                                     adpcmcomp(&sb);
  1263.                                 }
  1264.                                 if (lpccompress) {
  1265.                                     lpccomp(&sb);
  1266.                                 }
  1267.                                 shipSoundBuffer(hwnd, pClientData);
  1268.                             }
  1269.                         }        
  1270.  
  1271.                         if (bread == 0) {
  1272.                             KillTimer(hwnd, 2);
  1273.                             pClientData->state = pClientData->wantsInput ? SendingLiveAudio : Idle;
  1274.                             DragAcceptFiles(hwnd, TRUE);
  1275. #ifdef SHOW_STATE                            
  1276.                             InvalidateRect(hwnd, NULL, TRUE);
  1277.                             UpdateWindow(hwnd);
  1278. #endif                            
  1279.                             return 0;
  1280.                         }
  1281.                         pClientData->cbSent += bread;
  1282. #ifdef SHOW_STATE
  1283.                         InvalidateRect(hwnd, NULL, TRUE);
  1284.                         UpdateWindow(hwnd);
  1285. #endif                        
  1286.  
  1287.                         // If window isn't immortal, reset the timeout
  1288.                         if (pClientData->timeout > 0) {
  1289.                             pClientData->timeout = 0;
  1290.                         }
  1291.             
  1292.                         /* The following code is needed because when we're reading
  1293.                            sound from a file, as opposed to receiving it in real
  1294.                            time from the CODEC, we must meter out the samples
  1295.                            at the rate they will actually be played by the destination
  1296.                            machine.  For 8000 samples per second, this amounts
  1297.                            to 125 microseconds per sample, minus the time we spent
  1298.                            compressing the data (which is substantial for GSM) and
  1299.                            a fudge factor, kOverhead, which accounts for the time
  1300.                            spent in executing the delay itself and getting control
  1301.                            back after it's done.  If sound files pause periodically
  1302.                            (when the sending machine isn't loaded), you may need
  1303.                            to reduce the delay parameters.  If they're too low,
  1304.                            however, data will be lost when sending long sound files. */
  1305.             
  1306. #define kOverhead 25000
  1307.                         et = ((bread * 125L) - kOverhead) -
  1308.                             ((GetTickCount() - startTicks) * 1000);
  1309.                         if (et <= 0) {
  1310.                             et = 10;
  1311.                         }
  1312.                         SetTimer(hwnd, 2, (UINT) (et / 1000), NULL);
  1313. #ifdef DBT            
  1314. if (!IsIconic(hwnd)) {
  1315.     HDC hdc = GetDC(hwnd);
  1316.                             
  1317.     WinPrintf(hdc, 6, 1, "Timer reset to %d ms.", (UINT) (et / 1000));
  1318.     ReleaseDC(hwnd, hdc);        
  1319. }
  1320. #endif            
  1321.                 }
  1322.                 
  1323.                 /*    Timer indicating a periodic PGP poll is underway.
  1324.                        If PGP has finished writing the decoded session key
  1325.                        file, read it into the connection structure and put
  1326.                        it into effect, then sweep up after PGP.  */
  1327.                        
  1328.                 if (wParam == 3) {
  1329.                     HFILE kfile = _lopen(pClientData->pgpFileName,
  1330.                                         READ_WRITE | OF_SHARE_EXCLUSIVE);
  1331.                     
  1332.                     if (kfile == HFILE_ERROR) {
  1333.                         //    Still not done.  Reset the timer
  1334.                         SetTimer(hwnd, 3, 1000, NULL);
  1335.                     } else {
  1336.                         if (_lread(kfile, pClientData->pgpkey, 17) == 17) {
  1337.                             char yfn[MAX_PATH];
  1338.                             int i;
  1339.                             unsigned char ow[16];
  1340.                             
  1341.                             pClientData->pgpkey[0] = TRUE;
  1342.                             
  1343.                             //    Overwrite the session key on disc
  1344.                             
  1345.                             _llseek(kfile, 0L, 0);
  1346.                             for (i = 0; i < 16; i++) {
  1347.                                 ow[i] = 0xFF;
  1348.                             }
  1349.                             _lwrite(kfile, ow, 16);
  1350.                             _llseek(kfile, 0L, 0);
  1351.                             for (i = 0; i < 16; i++) {
  1352.                                 ow[i] = 0;
  1353.                             }
  1354.                             _lwrite(kfile, ow, 16);
  1355.                             
  1356.                             _lclose(kfile);
  1357.                             _fstrcpy(yfn, pClientData->pgpFileName);
  1358.                             _unlink(yfn);
  1359.                             _fstrcat(yfn, ".TMP");
  1360.                             _unlink(yfn);
  1361.                             pClientData->pgpFileName[0] = 0;
  1362.                             KillTimer(hwnd, 3); 
  1363.                         } else {
  1364.                             pClientData->pgpkey[0] = FALSE;
  1365.                             SetTimer(hwnd, 3, 1000, NULL);
  1366.                             _lclose(kfile);
  1367.                         }
  1368.                     }
  1369.                 }
  1370.                 
  1371.                 /*    Timer indicating a periodic PGP poll is underway.
  1372.                        If PGP has finished writing the encoded session key
  1373.                        file, read it into the connection structure and put
  1374.                        it into effect, then sweep up after PGP.  */
  1375.                        
  1376.                 if (wParam == 4) {
  1377.                     HFILE kfile = _lopen(pClientData->opgpFileName,
  1378.                                     READ | OF_SHARE_EXCLUSIVE);
  1379.                     
  1380.                     if (kfile == HFILE_ERROR) {
  1381.                         //    Still not done.  Reset the timer
  1382.                         SetTimer(hwnd, 4, 1000, NULL);
  1383.                     } else {
  1384.                         int len;
  1385.                         
  1386.                         if ((len = _lread(kfile, ebuf.buffer.buffer_val, BUFL)) > 0) {
  1387.                             int i;
  1388.                             char yfn[MAX_PATH];
  1389.                             
  1390.                             ebuf.buffer.buffer_len = len;
  1391.                             pClientData->opgpkey[0] = TRUE;        // Activate outbound PGP key
  1392.                             ebuf.compression = fKeyPGP;
  1393.                             {
  1394.                                 char gh[MAX_HOST];
  1395.                                 
  1396.                                 gethostname(gh, sizeof gh);
  1397.                                 if (strlen(gh) > ((sizeof ebuf.sendinghost) - 1)) {
  1398.                                     gh[(sizeof ebuf.sendinghost) - 1] = 0;
  1399.                                 }
  1400.                                 strcpy(ebuf.sendinghost, gh);
  1401.                             }
  1402.                             revlong(&ebuf.compression);
  1403.                             revlong(&ebuf.buffer.buffer_len);
  1404.                             
  1405.                             for (i = 0; i < 3; i++) {
  1406.                                 if (writeOutput(pClientData, (LPSTR) &ebuf,
  1407.                                         (int) ((sizeof(struct soundbuf) - BUFL) +
  1408.                                         len)) < 0) {
  1409.                                     break;
  1410.                                 }
  1411.                             }
  1412.                             _lclose(kfile);
  1413.                             
  1414.                             _fstrcpy(yfn, pClientData->opgpFileName);
  1415.                             _unlink(yfn);
  1416.                             yfn[_fstrlen(yfn) - 3] = 0;
  1417.                             _fstrcat(yfn, "TMP");
  1418.                             
  1419.                             //    Overwrite the session key on disc
  1420.                             
  1421.                             kfile = _lopen(yfn, READ_WRITE | OF_SHARE_EXCLUSIVE);
  1422.                             if (kfile != HFILE_ERROR) {
  1423.                                 int i;
  1424.                                 unsigned char ow[16];
  1425.                                 
  1426.                                 for (i = 0; i < 16; i++) {
  1427.                                     ow[i] = 0xFF;
  1428.                                 }
  1429.                                 _lwrite(kfile, ow, 16);
  1430.                                 _llseek(kfile, 0L, 0);
  1431.                                 for (i = 0; i < 16; i++) {
  1432.                                     ow[i] = 0;
  1433.                                 }
  1434.                                 _lwrite(kfile, ow, 16);
  1435.                                 _lclose(kfile);
  1436.                             }
  1437.                             _unlink(yfn);
  1438.                             pClientData->opgpFileName[0] = 0;
  1439.                             KillTimer(hwnd, 4); 
  1440.                         } else {
  1441.                             SetTimer(hwnd, 4, 1000, NULL);
  1442.                             _lclose(kfile);
  1443.                         }
  1444.                     }
  1445.                 }
  1446.                 
  1447.                 /*    Cadence timer regulating retrieval of a face
  1448.                     image from the connected host.  */
  1449.                 
  1450.                 if (wParam == 5) {
  1451.                     int makereq = FALSE;
  1452.         
  1453.                     /* If a face file transfer is in progress, request
  1454.                        the next block or, if it's time, re-issue the last
  1455.                        request if the timeout has expired. */
  1456.         
  1457.                     if (pClientData->face_stat == FSreply) {
  1458.                         makereq = TRUE;
  1459.                         pClientData->face_retry = 0;
  1460. #ifdef TRACE_FACE
  1461.                         {    char s[MAX_HOST + 80];
  1462.                         
  1463.                             wsprintf(s, "Request face data at %ld from %s\r\n",
  1464.                                 pClientData->face_address, pClientData->szHost);
  1465.                             OutputDebugString(s);
  1466.                         }
  1467. #endif                        
  1468.                     } else if (pClientData->face_stat == FSrequest) {
  1469.                         pClientData->face_timeout++;
  1470.                         if (pClientData->face_timeout >= FaceTimeout) {
  1471. #ifdef TRACE_FACE
  1472.                             {    char s[MAX_HOST + 80];
  1473.                             
  1474.                                 wsprintf(s, "Retry %d reissue face data request at %ld from %s\r\n",
  1475.                                         pClientData->face_retry, pClientData->face_address,
  1476.                                         pClientData->szHost);
  1477.                                 OutputDebugString(s);
  1478.                             }
  1479. #endif                        
  1480.                             if (pClientData->face_retry > FaceMaxRetries) {
  1481. /*                            
  1482.                                 if (pClientData->face_file != NULL) {
  1483.                                     fclose(c->face_file);
  1484.                                     c->face_file = NULL;
  1485.                                 }
  1486.                                 unlink(c->face_filename);
  1487.                                 c->face_filename[0] = 0;
  1488. */                                
  1489.                                 pClientData->face_stat = FSabandoned;
  1490.                                 if (pClientData->face_bmp != NULL) {
  1491.                                     GlobalFreePtr(pClientData->face_bmp);
  1492.                                     pClientData->face_bmp = NULL;
  1493.                                 }
  1494.                                 KillTimer(hwnd, 5);
  1495. #ifdef TRACE_FACE
  1496.                                 {    char s[MAX_HOST + 80];
  1497.                                 
  1498.                                     wsprintf(s, "Timeout, no face image available for %s\r\n",
  1499.                                             pClientData->szHost);
  1500.                                     OutputDebugString(s);
  1501.                                 }
  1502. #endif                        
  1503.                             } else {
  1504.                                 makereq = TRUE;
  1505.                                 pClientData->face_retry++;
  1506.                             }
  1507.                         }
  1508.                     } else {
  1509.                         KillTimer(hwnd, 5);            // Terminated due to data format error
  1510. #ifdef TRACE_FACE
  1511.                         OutputDebugString("Face timer shut down.\r\n");
  1512. #endif                        
  1513.                     }
  1514.         
  1515.                     if (makereq) {
  1516.                         pClientData->face_stat = FSrequest;
  1517.                         pClientData->face_timeout = 0;
  1518.                         sb.compression = htonl(fFaceData | faceRequest);
  1519.                         sb.buffer.buffer_len = htonl(pClientData->face_address);
  1520.                         if (writeOutput(pClientData, (LPSTR) &sb, sizeof(soundbuf) - BUFL) < 0) {
  1521.                              pClientData->face_stat = FSabandoned;
  1522. // *** CLEAN UP DEBRIS                                
  1523.                         }
  1524.                     }
  1525.                 }
  1526.             }
  1527.             return 0;
  1528.     }
  1529.     return DefMDIChildProc(hwnd, nMessage, wParam, lParam);
  1530. }
  1531.  
  1532.  
  1533.